package in.equilibr.ingredients.dao;

import in.equilibr.ingredients.model.Ingredient;
import in.equilibr.ingredients.service.IngredientService;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.lucene.search.Query;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.jpa.Search;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
// java-tx -> spring-orm dependency


@Repository
public class IngredientDao {	
	@Autowired
	private IngredientService ingredientService;
	
	@PersistenceContext
	private EntityManager entityManager;
	
	@SuppressWarnings("unchecked")
	public List<Ingredient> getIngredients(int limit) {
		javax.persistence.Query query = entityManager.createQuery("from Ingredient order by calories desc");
		query.setMaxResults(limit);
		return query.getResultList();
	}
	
	@Transactional
	public void addIngredient(Ingredient ingredient) {
		entityManager.merge(ingredient);
	}
	
	@Transactional
	public Boolean deleteIngredientById(int id) {
		// FIXME: it is bullshit here! find by id function should be implemented whit in dao object
		Ingredient ingredientToDelete = ingredientService.findIngredientById(this.getIngredients(Integer.MAX_VALUE), id);
		if(ingredientToDelete != null) {
			entityManager.remove(ingredientToDelete);
			return true;
		}
		return false;
	}
	
	@SuppressWarnings("unchecked")
	public List<Ingredient> searchIngredient(String term) {
		return entityManager.createQuery("from Ingredient where Name like '" + term + "%'").getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public List<String> searchIngredientName(String term) {
		return entityManager.createQuery("select name from Ingredient where Name like '" + term + "%' order by calories desc").getResultList();
	}
	
	@SuppressWarnings("unchecked")
	@Transactional
	public List<String> searchSimilarIngredients(String term) {
		FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
		QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Ingredient.class).get();
		Query luceneQuery = qb.keyword().fuzzy().onField("name").matching(term).createQuery();
		
		FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(luceneQuery, Ingredient.class);
		List<Ingredient> ingredients = fullTextQuery.getResultList();
		
		// just ingredient name not whole object? (calories?)
		List<String> ingredientNames = new ArrayList<String>();
		
		for(Ingredient currentIngredient: ingredients) {
			ingredientNames.add(currentIngredient.getName());
		}
		
		fullTextEntityManager.close();
		return ingredientNames;
	}

	// TODO: WTF?
	public void createSearchIndex() throws InterruptedException {
		FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
		fullTextEntityManager.createIndexer(Ingredient.class).startAndWait();
		fullTextEntityManager.close();
	}
}
